<template>
  <div class="o-datepicker">
    <DatePicker
      :type="type"
      :format="renderOpts.props.format"
      :value="value"
      :placeholder="renderOpts.props.placeholder"
      @on-change="onChange"
      @on-open-change="onOpenChange"
      @on-clear="onClear"
      :disabled="renderOpts.props.disabled"
      :clearable="true"
      transfer
      :class="'align-' + align"
      ref="picker"
      v-if="
        ['datetime', 'date', 'datetimerange', 'daterange'].indexOf(type) > -1
      "
    ></DatePicker>
    <TimePicker
      :type="type"
      :format="renderOpts.props.format"
      :class="'align-' + align"
      :value="value"
      :placeholder="renderOpts.props.placeholder"
      @on-change="onChange"
      @on-open-change="onOpenChange"
      @on-clear="onClear"
      :clearable="true"
      :disabled="renderOpts.props.disabled"
      transfer
      ref="picker"
      v-else-if="['time', 'timerange'].indexOf(type) > -1"
    ></TimePicker>
  </div>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator';
import { DatePicker, TimePicker, Input } from 'view-design';
import { Tsrv } from '@/services';

@Component
export default class oDatePicker extends Vue {
  // modify by wiz
  public compName: string = 'oDatepicker';

  /**
   * props
   */
  @Prop() renderOpts: any;

  @Prop() params: any;

  private open = false;

  private value = null;

  private type = 'datetime';

  private format = 'yyyy-MM-dd HH:mm:ss';

  private dataFormat = 'yyyy-MM-dd HH:mm:ss.SSS';

  private pickerInput: Input | null = null;

  private align = 'left';

  /**
   * data
   */
  @Watch('params')
  onParamsChange() {
    this.initProps();
    this.setValue();
  }

  @Watch('renderOpts')
  onRenderOptsChange() {
    this.initProps();
    this.init();
  }

  mounted() {
    this.initProps();
    this.init();
    this.setValue();
  }

  private initProps() {
    if (this.params.property) {
      const items = this.params.$form.items;
      const find = Tsrv.utils.find(
        items,
        el => el.field === this.params.property
      );
      if (find) {
        this.align = find.align || 'left';
      }
    } else {
      this.align = this.params.column.align || 'left';
    }
  }

  public init() {
    this.type = this.renderOpts.props.type;
    this.format = this.renderOpts.props.format;
    this.dataFormat = this.renderOpts.props.dataFormat;
    if (['date', 'daterange'].indexOf(this.type) > -1) {
      this.pickerInput = (this.$refs.picker as DatePicker)
        .$children[0] as Input;
      if (!this.dataFormat) this.dataFormat = 'yyyy-MM-dd';
    } else if (['datetime', 'datetimerange'].indexOf(this.type) > -1) {
      this.pickerInput = (this.$refs.picker as DatePicker)
        .$children[0] as Input;
      if (!this.dataFormat) this.dataFormat = 'yyyy-MM-dd HH:mm:ss.SSS';
    } else if (['time', 'timerange'].indexOf(this.type) > -1) {
      this.pickerInput = (this.$refs.picker as TimePicker)
        .$children[0] as Input;
      if (!this.dataFormat) this.dataFormat = 'HH:mm:ss';
    }
    this.pickerInput['handleFocus'] = () => {
      this.emitEvent('focus');
    };
    this.pickerInput['handleBlur'] = e => {
      this.onBlur(e);
      this.emitEvent('blur');
    };
  }

  public focus() {
    (this.pickerInput.$el as HTMLInputElement).click();
    this.pickerInput.focus();
  }

  resetValue() {
    this.setValue(null);
    this.setTableValue(null);
  }

  onBlur(ev) {
    if (ev && ev.target) {
      this.onChange(ev.target.value);
    }
  }

  setValue(val: null | string | undefined = undefined) {
    let value = null;
    const v =
      val !== undefined
        ? val
        : this.params.property
        ? this.params.data[this.params.property]
        : this.params.row[this.params.column.property];
    if (v !== null && v) {
      if (this.type === 'datetime' || this.type === 'date') {
        value = Tsrv.utils.toStringDate(`${v}+0800`, `${this.format}ZZ`);
      } else if (this.type === 'datetimerange' || this.type === 'daterange') {
        const arr = v.split(' - ');
        value = [
          Tsrv.utils.toStringDate(`${arr[0]}+0800`, `${this.format}ZZ`),
          Tsrv.utils.toStringDate(`${arr[1]}+0800`, `${this.format}ZZ`)
        ];
      } else if (this.type === 'time') {
        value = this.getTime(v)[0];
      } else if (this.type === 'timerange') {
        const arr = v.split(' - ');
        value = `${this.getTime(arr[0])[0]} - ${this.getTime(arr[1])[0]}`;
      }
    } else {
      if (this.type === 'datetimerange' || this.type === 'daterange') {
        value = [null, null];
      }
    }
    this.value = value;
  }

  getPkTime(timeStr: string) {
    const timezone = 8;
    const offset = new Date(timeStr).getTimezoneOffset();
    const now = new Date(timeStr).getTime();
    const time = now + offset * 60 * 1000 + timezone * 60 * 60 * 1000;
    return [
      Tsrv.utils.toDateString(time, this.format),
      Tsrv.utils.toDateString(time, this.dataFormat)
    ];
  }

  testTime(time) {
    const reg = new RegExp('^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$');
    return reg.test(time);
  }

  getTime(timeStr: string) {
    if (timeStr) {
      if (timeStr.indexOf(':') > -1) {
        const reg = new RegExp(
          /[HH|hh]{2}(\S*?)[MM|mm]{2}(\S*?)[SS|ss]{2}(.*)/
        );
        const arr = timeStr.split(':');
        const fArr = this.format.match(reg);
        const dFArr = this.dataFormat.match(reg);
        fArr.shift();
        dFArr.shift();
        if (fArr && dFArr) {
          return [
            arr[0] + fArr[0] + arr[1] + fArr[1] + arr[2] + fArr[2],
            arr[0] + dFArr[0] + arr[1] + dFArr[1] + arr[2] + dFArr[2]
          ];
        }
      }
    }
    return [null, null];
  }

  setTableValue(val: string | string[] | null) {
    if (val !== null) {
      let value = [null, null];
      if (
        this.type === 'datetime' ||
        this.type === 'date' ||
        this.type === 'time'
      ) {
        val = val as string;
        if (!isNaN(Date.parse(val)) && this.type !== 'time') {
          value = this.getPkTime(val);
        } else if (this.testTime(val) && this.type === 'time') {
          value = this.getTime(val);
        }
      } else if (
        this.type === 'datetimerange' ||
        this.type === 'daterange' ||
        this.type === 'timerange'
      ) {
        let valArr: string[] = ['', ''];
        if (Tsrv.utils.isString(val) && val.indexOf(' - ') > -1) {
          valArr = (val as string).split(' - ');
        } else if (Tsrv.utils.isArray(val) && val.length === 2) {
          valArr = val as string[];
        }
        if (
          !isNaN(Date.parse(valArr[0])) &&
          !isNaN(Date.parse(valArr[1])) &&
          this.type !== 'timerange'
        ) {
          const first = this.getPkTime(valArr[0]);
          const second = this.getPkTime(valArr[1]);
          value = [`${first[0]} - ${second[0]}`, `${first[1]} - ${second[1]}`];
        } else if (
          this.testTime(valArr[0]) &&
          this.testTime(valArr[1]) &&
          this.type === 'timerange'
        ) {
          const first = this.getTime(valArr[0]);
          const second = this.getTime(valArr[1]);
          value = [`${first[0]} - ${second[0]}`, `${first[1]} - ${second[1]}`];
        }
      }
      if (this.params.property) {
        this.params.data[this.params.property] = value[1];
      } else {
        this.params.row[this.params.column.property] = value[1];
      }
      if (value !== null) {
        this.value = value[0];
      }
    } else {
      if (this.params.property) {
        this.params.data[this.params.property] = val;
      } else {
        this.params.row[this.params.column.property] = val;
      }

      this.value = null;
    }
  }

  onOpenChange(e) {
    if (!e) {
      this.emitEvent('dochange');
    }
  }

  onChange(e) {
    if (e === '') {
      this.setTableValue(null);
    } else {
      this.setTableValue(e);
    }
    this.emitEvent('dochange');
  }

  emitEvent(event: string) {
    const ev = this.renderOpts.events;
    // 深拷贝有问题
    // const params = Tsrv.utils.clone(this.params);
    const params = Tsrv.utils.cloneNoMatchVue(this.params, true);
    params['from'] = 'inputtext';
    params.from = 'datepicker';
    for (const action in ev) {
      if (ev[action] && action === `on-${event}`) {
        ev[action](params);
      }
    }
  }

  onClear() {
    this.setTableValue(null);
  }
}
</script>
<style lang="scss" scoped>
.o-datepicker {
  width: 100%;
  > .ivu-date-picker {
    width: 100%;
  }
}
</style>
